package config

import (
	"fmt"
	"gogame/game/manage/module"
	"gogame/lib"
	"gogame/lib/database/mongo"
	myRedis "gogame/lib/database/redis"
	"gogame/logger"
	"sync"
)

/*
配置管理 统一管理所有配置
configstruct中的struct由Luban生成
github地址：https://github.com/focus-creative-games/luban
gitee地址：https://gitee.com/focus-creative-games/luban

每个配置对应一个文件，文件名格式：config_配置名.go
config_配置名.go 由 json2go.py自动生成

若json是excel转出来的，需要继承struct中对应的结构
demo文件：当前目录下的config_hero.go

若json是自定义的json格式，需要继承jsonbase文件中的JsonHandle
demo文件：当前目录下的config_errormsg.go


*/

type Configs struct {
	Hero *Hero
	Item *Item
	Task *Task

	// 自定义json
	ErrorMsg *ErrorMsg
	Other    *Other
}

type ManageStruct struct {
	sync.RWMutex
	configs              Configs                    // 所有配置集合
	configMap            map[string]struct{}        // 配置是否加载过
	name2ConfigInterface map[string]configInterface // 配置对应的接口

}

var Manage = &ManageStruct{
	configs:              Configs{},
	configMap:            make(map[string]struct{}),
	name2ConfigInterface: make(map[string]configInterface),
}

// 这里的单独使用 g.GC会导致循环引用
var (
	Redis      = myRedis.InitRedis()
	CrossRedis = myRedis.InitCrossRedis()
	GC         = Manage
	M          = module.Manage
	C          = lib.Common
	Mdb        = mongo.InitMongo()
	CrossMdb   = mongo.InitCrossMongo()
	Event      = lib.GlobalEvent
)

// RegisterConfigInterface 配置类接口注册
func RegisterConfigInterface(name string, i configInterface) {
	Manage.name2ConfigInterface[name] = i
}

// SetLoad 设置已加载
func SetLoad(name string) {
	Manage.configMap[name] = struct{}{}
}

type configInterface interface {
	Load(any) error                // 配置加载到
	SetLoad()                      // 设置已加载标记
	UnMarshal([]byte) (any, error) // 文件内容解析
}

// Reload 热更新
func (m *ManageStruct) Reload(names ...string) {
	m.Lock()
	defer m.Unlock()
	// 重载全部
	if len(names) == 0 {
		m.configMap = make(map[string]struct{})
	} else {
		// 重载指定文件
		for _, name := range names {
			delete(m.configMap, name)
		}
	}
}

// Load 加载配置
func (m *ManageStruct) Load(name string) {
	m.RLock()
	_, ok := m.configMap[name]
	m.RUnlock()

	// 配置已初始化
	if ok {
		return
	}

	m.Lock()
	defer m.Unlock()

	//logger.Print("正在初始化配置【%s】", name)

	// 文件路径校验
	_filePath := lib.GetFilePath(fmt.Sprintf("samejson/%s.json", name))
	if !lib.IsFileExist(_filePath) {
		_filePath = lib.GetFilePath(fmt.Sprintf("json/%s.json", name))
	}
	if !lib.IsFileExist(_filePath) {
		logger.Print("配置【%s】不存在!!", name)
		return
	}

	// 读取文件内容
	_fileData := lib.ReadFile(_filePath)
	if _fileData == nil {
		return
	}

	_configInterface := m.name2ConfigInterface[name]
	// 文件解析
	_data, err := _configInterface.UnMarshal(_fileData)
	if err != nil {
		logger.WorkerLog.Warn(fmt.Sprintf("配置【%s】解析失败！！err->%s", name, err))
		return
	}

	// load...
	err = _configInterface.Load(_data)
	if err != nil {
		logger.WorkerLog.Warn(fmt.Sprintf("配置【%s】加载失败！！err->%s", name, err))
		return
	}

	// 标识该配置已加载
	_configInterface.SetLoad()
}

/* ------------------- 以下为config的初始化，首次访问才加载 避免使用any而使用反射 ------------------- */
/*
使用方法:
获取id为xx的英雄配置：g.GC.Hero().Get(xx)
获取所有英雄配置：g.GC.Hero().GetList()
*/

// Hero 英雄
func (m *ManageStruct) Hero() *Hero {
	m.Load(m.configs.Hero.Name)
	return m.configs.Hero

}

// Item 道具
func (m *ManageStruct) Item() *Item {
	m.Load(m.configs.Item.Name)
	return m.configs.Item

}

// Task 任务
func (m *ManageStruct) Task() *Task {
	m.Load(m.configs.Task.Name)
	return m.configs.Task

}

// ErrorMsg 错误信息
func (m *ManageStruct) ErrorMsg() *ErrorMsg {
	m.Load(m.configs.ErrorMsg.Name)
	return m.configs.ErrorMsg

}

// Other 敏感词检测
func (m *ManageStruct) Other() *Other {
	m.Load(m.configs.Other.Name)
	return m.configs.Other

}
